package anatex.kea.genex.extractor;

import java.text.BreakIterator;
import java.util.*;
import java.util.regex.*;


import org.hibernate.validator.constraints.ScriptAssert;
import org.apache.commons.collections.bidimap.*;
import org.apache.commons.collections.list.TreeList;
import org.annolab.tt4j.*;

import anatex.kea.genex.GenEx;

/**
 * 
 * @author genadi
 *
 */

public class Assessor {

	final static int FORCED_STEM_LIMIT = 500;
	
	protected String text, lcText;
	protected Parameters parameters;
	TreeSet<Object[]> topSingleStems, topStemPhrases = null;
	public static Comparator<Object[]> cmp = new Comparator<Object[]>() {
		
		@Override
		public int compare(Object[] o1, Object[] o2) {
			Double d2 = (Double)o2[1];
			Double d1 = (Double)o1[1];
			
			if (d2 > d1) {
				return 1;
			}
			
			return -1;
		}
	};;
	
	public Assessor (String t, Parameters p) {
		
		text = t;
		lcText = text.toLowerCase();
		parameters = p;
		
	}
	
	protected TreeSet<Object[]> scoreStems(ArrayList<String> s, Boolean forceLimit) {
		
		TreeSet<Object[]> scored = new TreeSet<Object[]>(cmp);
		if (null != topSingleStems) {
			scored.addAll(topSingleStems);
		}
		HashMap<String, Boolean> scoredIndex = new HashMap<String, Boolean>();
		
		Pattern p;
		Matcher m;
		Iterator<String> it = s.iterator();
		Integer FLT = Integer.valueOf(parameters.get(Parameters.FIRST_LOW_THRESH).toString());
		Double FLF = Double.valueOf(parameters.get(Parameters.FIRST_LOW_FACTOR).toString());
		Integer FHT = Integer.valueOf(parameters.get(Parameters.FIRST_HIGH_THRESH).toString());
		Double FHF = Double.valueOf(parameters.get(Parameters.FIRST_HIGH_FACTOR).toString());
		Integer NW = forceLimit ? FORCED_STEM_LIMIT : Integer.valueOf(parameters.get(Parameters.NUM_WORKING).toString());
		Double FTWO = Double.valueOf(parameters.get(Parameters.FACTOR_TWO_ONE).toString());
		Double FTHO = Double.valueOf(parameters.get(Parameters.FACTOR_THREE_ONE).toString());
		
		while (it.hasNext()) {
			String stem = it.next();
			
			if (scoredIndex.containsKey(stem)) {
				continue;
			}
			
			p = Pattern.compile(stem.trim().replaceAll("\\s", "[^\\s]*?[\\s]*?") + "[^\\s]*?", Pattern.CASE_INSENSITIVE | Pattern.UNICODE_CASE);
			m = p.matcher(lcText);
			int cnt = 0;
			int first = 0;
			Double score;
			
			while (m.find()) {
				if (0 == cnt) {
					first = m.start();
				}
				cnt ++;
			}
			
			//calculate stem score
			score = new Double(cnt);
			if (first < FLT) {
				score *= FLF;
			} else if (first > FHT) {
				score *= FHF;
			}
			
			int sCnt = 1;
			if (-1 != stem.indexOf(' ')) {
				sCnt = 2;
				
				if (-1 != stem.indexOf(' ', stem.indexOf(' '))) {
					sCnt = 3;
				}
			}
			
			switch (sCnt) {
				case 2 :
					score *= FTWO;
					break;
					
				case 3 :
					score *= FTHO;
					break;
			}
			
			Object[] item = {stem, score};
			scored.add(item);
			scoredIndex.put(stem, true);
			
			if (scored.size() > NW) {
				Object[] l = scored.pollLast();
				scoredIndex.remove(l[0]);
			}
		}
		
		return scored;
	}
	
	public TreeSet<Object[]> getTopSingleStems(ArrayList<String> stems) {
		
		if (null == topSingleStems) {
			topSingleStems = scoreStems(stems, false);
		}
		
		return topSingleStems;
	}
	
	public TreeSet<Object[]> getTopStemPhrases(ArrayList<String> stemPhrases) {
		
		if (null == topStemPhrases) {
			topStemPhrases = new TreeSet<Object[]>(cmp);
			TreeSet<Object[]> stemPhraseCandidates = scoreStems(stemPhrases, true);
			
			Iterator<Object[]> cIt;
			Iterator<Object[]> rIt = topSingleStems.iterator();
			String stemPhrase;
			
			while (rIt.hasNext()) {
				Object[] stemItem = rIt.next();
				String singleStem = (String)stemItem[0];
				Double score = (Double)stemItem[1];
				cIt = stemPhraseCandidates.iterator();
				
				while (cIt.hasNext()) {
					stemPhrase = (String)cIt.next()[0];
					
					if (-1 != stemPhrase.indexOf(singleStem)) {
						Object[] item = {stemPhrase.toString(), score}; 
						
						//do not allow duplicates
						if (! topStemPhrases.contains(item)) {
							topStemPhrases.add(item);
						}
						
						break;
					}
				}
			}
		}
		
		return topStemPhrases;
	}
	
}
